# !/usr/bin/env python
# -*-coding:utf-8 -*-
"""
# File       : api_decorator.py
# Time       ：2023/7/7 21:29
# Author     ：Y-aong
# version    ：python 3.7
# Description：
    处理api接口的装饰器
    Decorators that handle api interfaces
"""

import traceback
from functools import wraps

import flask_restx
from jwt import DecodeError
from marshmallow import ValidationError
from sqlalchemy.exc import IntegrityError

from public.api_exceptions.api_exceptions import JWTVerifyException
from public.api_utils.jwt_utils import JWTUtils
from public.base_model import session_scope
from public.base_response import generate_response
from public.logger import logger
from flask import request


def publish_logger_info(headers: dict, state: str):
    """发布日志信息，日志信息格式为 【username】 【行为】 【状态】"""
    from apis.notice.model.logger_info import LoggerInfo

    authorization = headers.get('Authorization')
    if authorization and authorization.startswith('Bearer '):
        token = authorization.replace('Bearer ', '')
        payload = JWTUtils().verify_token(token)
        username = payload.get('login_value')
        api_path = request.path
        method = request.method
        action = f'{request.path}-{request.method}'
        message = f'用户【{username}】{action}——{state}'
        with session_scope() as session:
            logger_info = {
                'api_path': api_path,
                'method': method,
                'state': state,
                'visitor': username,
                'message': message,
            }
            obj = LoggerInfo(**logger_info)
            session.add(obj)
            session.commit()


def handle_api_error():
    """处理api异常，并记录异常信息"""
    def decorator(func):
        @wraps(func)
        def wrapper(self):
            from orderlines.utils.exceptions import OrderLinesRunningException
            headers = request.headers
            try:
                res = func(self)
                publish_logger_info(headers, '成功')
                return res
            except IntegrityError as e:
                logger.info(f"request_url::{request.url},\ntraceback::{traceback.format_exc()}, {e}")
                return generate_response(message=f'db parameter repetition.', code=400)
            except ValueError as e:
                logger.info(f"request_url::{request.url},\ntraceback::{traceback.format_exc()}, {e}")
                publish_logger_info(headers, '失败')
                return generate_response(message=f'{e}', code=400)
            except ValidationError as e:
                logger.error(f"request_url::{request.url},\ntraceback::{traceback.format_exc()}, {e}")
                publish_logger_info(headers, '失败')
                return generate_response(message='Client parameters are abnormal.', code=400)
            except JWTVerifyException as e:
                logger.error(f"request_url::{request.url},\ntraceback::{traceback.format_exc()}, {e}")
                publish_logger_info(headers, '失败')
                return generate_response(message='The current token has expired.', code=400)
            except DecodeError as e:
                logger.error(f"request_url::{request.url},\ntraceback::{traceback.format_exc()}, {e}")
                publish_logger_info(headers, '失败')
                return generate_response(message='jwt parse failed.', code=400)
            except OrderLinesRunningException as e:
                logger.error(f"request_url::{request.url},\ntraceback::{traceback.format_exc()}, {e}")
                publish_logger_info(headers, '失败')
                return generate_response(message=f'orderlines run failure, {e}.', code=400)
            except flask_restx.fields.MarshallingError as e:
                logger.error(f"request_url::{request.url},\ntraceback::{traceback.format_exc()}, {e}")
                publish_logger_info(headers, '失败')
                return generate_response(message=f'params is not valid, {e}.', code=400)
            except Exception as e:
                logger.info(f"request_url::{request.url},\ntraceback::{traceback.format_exc()}, {e}")
                publish_logger_info(headers, '失败')
                return generate_response(message='Server exception.', code=500)

        return wrapper

    return decorator
